﻿#pragma
#include <SDL.h>
#include <QDebug>

/// <summary>
/// SDL渲染视频工具类
/// </summary>
class SDLRenderUtil {
private:
	SDL_Window* sdlWindow;
	SDL_Renderer* sdlRender;
	SDL_Texture* sdlTexture;
public:
	int width = 400;
	int height = 300;
	int m_scale_width = 0;
	int m_scale_height = 0;
	void* winId;
	/// <summary>
	/// RGBA = 0,
	/// ARGB,
	/// RGB24,
	/// YUV420P,
	/// </summary>
	int PIX_FMT = 0;
public:
	bool Init() {
		Close();
		//初始化SDL库
		if (SDL_Init(SDL_INIT_VIDEO)) {
			qDebug() << "SDL初始化失败->" << SDL_GetError();
			return false;
		}
		//2 生成SDL 窗口
		if (winId) {
			sdlWindow = SDL_CreateWindowFrom(winId);
		}
		else {
			sdlWindow = SDL_CreateWindow("SDL窗口",
				SDL_WINDOWPOS_CENTERED,//窗口位置
				SDL_WINDOWPOS_CENTERED,
				width, height,
				SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
			);
		}

		if (!sdlWindow)
		{
			qDebug() << "SDL窗口创建失败->" << SDL_GetError();
			return false;
		}

		//3 生成渲染器
		sdlRender = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED);
		if (!sdlRender)
		{
			qDebug() << "SDL渲染器创建失败->" << SDL_GetError();
			return false;
		}
		int pix_fmt_type = SDL_PIXELFORMAT_IYUV;
		switch (PIX_FMT) {
		case 0:
			pix_fmt_type = SDL_PIXELFORMAT_RGBA32;
			break;
		case 1:
			pix_fmt_type = SDL_PIXELFORMAT_ARGB32;
			break;
		case 2:
			pix_fmt_type = SDL_PIXELFORMAT_RGB24;
			break;
		case 3:
			pix_fmt_type = SDL_PIXELFORMAT_IYUV;
			break;
		case 4:
			pix_fmt_type = SDL_PIXELFORMAT_NV12;
			break;
		}
		//4 生成材质
		//SDL_PIXELFORMAT_ARGB8888
		sdlTexture = SDL_CreateTexture(sdlRender, pix_fmt_type,
			SDL_TEXTUREACCESS_STREAMING,// 可加锁
			width, height
		);
		if (!sdlTexture)
		{
			qDebug() << "SDL材质创建失败->" << SDL_GetError() << endl;
			return false;
		}
		//设定缩放算法，解决锯齿问题,线性插值算法
		SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
		return true;
	}

	bool Render(char* data)
	{
		//5 内存数据写入材质
		switch (PIX_FMT)
		{
		case 0:
		case 1:
			SDL_UpdateTexture(sdlTexture, NULL, data, width * 4);
			break;
		case 2:
			SDL_UpdateTexture(sdlTexture, NULL, data, width * 3);
			break;
		case 3:
			/*
			// 提取 Y、U、V 平面数据（关键！）
			size_t y_size = width * height;
			size_t uv_size = (width / 2) * (height / 2);
			uint8_t* y_data = (uint8_t*)data;
			uint8_t* u_data = y_data + y_size;
			uint8_t* v_data = u_data + uv_size;

			// 使用 SDL_UpdateYUVTexture 更新纹理
			SDL_UpdateYUVTexture(
				sdlTexture,
				NULL,          // 更新全区域
				y_data,        // Y平面指针
				width,         // Y步长 = 宽度（无填充）
				u_data,        // U平面指针
				width / 2,     // U步长 = 宽度/2（无填充）
				v_data,        // V平面指针
				width / 2      // V步长 = 宽度/2（无填充）
			);
			*/
			SDL_UpdateTexture(sdlTexture, NULL, data, width);
			break;
		}

		//6 清理屏幕
		SDL_RenderClear(sdlRender);

		SDL_Rect rect;
		SDL_Rect* prect = nullptr;
		if (m_scale_width > 0 && m_scale_height > 0)  //用户手动设置缩放
		{
			rect.x = 0; rect.y = 0;
			rect.w = m_scale_width;//渲染的宽高，可缩放
			rect.h = m_scale_height;
			prect = &rect;
			qDebug() << "开始渲染大窗口";
		}

		//7 复制材质到渲染器
		SDL_RenderCopy(sdlRender, sdlTexture,
			NULL,//原图位置和尺寸
			prect//目标位置和尺寸
		);
		//8 渲染
		SDL_RenderPresent(sdlRender);
		return true;
	}

	bool DrawFrame(const unsigned char* y, const unsigned char* u, const unsigned char* v,size_t ylinesize,size_t ulinesize,size_t vlinesize)
	{

		// 使用 SDL_UpdateYUVTexture 更新纹理
		SDL_UpdateYUVTexture(
			sdlTexture,
			NULL,          // 更新全区域
			y,        // Y平面指针
			ylinesize,         // Y步长 = 宽度（无填充）
			u,        // U平面指针
			ulinesize,     // U步长 = 宽度/2（无填充）
			v,        // V平面指针
			vlinesize      // V步长 = 宽度/2（无填充）
		);

		//6 清理屏幕
		SDL_RenderClear(sdlRender);

		SDL_Rect rect;
		SDL_Rect* prect = nullptr;
		if (m_scale_width > 0 && m_scale_height > 0)  //用户手动设置缩放
		{
			rect.x = 0; rect.y = 0;
			rect.w = m_scale_width;//渲染的宽高，可缩放
			rect.h = m_scale_height;
			prect = &rect;
			qDebug() << "开始渲染大窗口";
		}

		//7 复制材质到渲染器
		SDL_RenderCopy(sdlRender, sdlTexture,
			NULL,//原图位置和尺寸
			prect//目标位置和尺寸
		);
		//8 渲染
		SDL_RenderPresent(sdlRender);
		return true;
	}

	bool DrawFrame(const unsigned char* data, size_t linesize)
	{

		//更新材质
		SDL_UpdateTexture(sdlTexture, NULL, data, linesize);

		//6 清理屏幕
		SDL_RenderClear(sdlRender);

		SDL_Rect rect;
		SDL_Rect* prect = nullptr;
		if (m_scale_width > 0 && m_scale_height > 0)  //用户手动设置缩放
		{
			rect.x = 0; rect.y = 0;
			rect.w = m_scale_width;//渲染的宽高，可缩放
			rect.h = m_scale_height;
			prect = &rect;
			qDebug() << "开始渲染大窗口";
		}

		//7 复制材质到渲染器
		SDL_RenderCopy(sdlRender, sdlTexture,
			NULL,//原图位置和尺寸
			prect//目标位置和尺寸
		);
		//8 渲染
		SDL_RenderPresent(sdlRender);
		return true;
	}

	//初始化SDL事件
	bool isEventQuit()
	{
		//判断退出
		SDL_Event ev;
		SDL_WaitEventTimeout(&ev, 10);
		if (ev.type == SDL_QUIT)
		{
			Close();
			return true;
		}
		return false;
	}

	void Close()
	{
		if (sdlTexture) {
			SDL_DestroyTexture(sdlTexture);
			sdlTexture = NULL;
		}
		if (sdlRender)
		{
			SDL_DestroyRenderer(sdlRender);
			sdlRender = NULL;
		}
		if (sdlWindow) {
			SDL_DestroyWindow(sdlWindow);
			sdlWindow = NULL;
		}
	}
	static SDLRenderUtil* Get()
	{
		static SDLRenderUtil sdlRenderUtil;
		return &sdlRenderUtil;
	}
	static SDLRenderUtil* Create()
	{
		return new SDLRenderUtil();
	}
};